import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;


/*
 * 
 */
public class MainClass {

	private static final int DEFAULT_HOPS_COUNT = 1;
	private static int INVALID_VALUE = -1;
	private static int USERDATA_THREADS = 10;
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		//стандартные
		String headerName = "sunflowersteam";
		int hopsCount = DEFAULT_HOPS_COUNT;
		
		//данные из строки
		if (args.length >= 1) 
			headerName = args[0];
		
		if (args.length >= 2)
			hopsCount = Integer.parseInt(args[1]);
		
		//Запрашиваем id юзера через ScreenName без прокси
		long headerId = getHeadUserId(headerName);
		
		//проверка на валид id
		if (headerId == INVALID_VALUE) {
			System.out.println("MainClass.main() cant get user id - end");
			return;
		}
		
		//отладочная инфа о начале работы
		System.out.println("MainClass.main():HeaderName:" + headerName + " id:" + headerId + " hops count:" + hopsCount);
		
		//основная часть
		final GraphManager gm = new GraphManager(new Long(headerId));
		final ProxyManager pm = new ProxyManager("./proxy.txt");		

		//проверим, что прокси нашлись
		if (pm.proxiesSize() > 0) { 
			//по всем юзерам получили друзей
			if (getUsersFollowers(gm, pm, hopsCount)) {
				//если всё ок - запишем данные в файлы
				if (getUserData(gm, pm)) {
					gm.writeFollowersToFile("./followers.csv", false);
					gm.writeFollowersToFile("./followers.dot", true);
					System.out.println("MainClass.main():all userdata written in files, program ended.");
				} else {
					System.out.println("MainClass.main() getUserData returns false");
				}
			} else {
				System.out.println("MainClass.main() getUsersFollower returns false");
			}
		} else {
			System.out.println("MainClass.main() error:proxy file not found or empty");
		}

		
	}
	
	//получение данных по юзерам
	private static boolean getUserData(GraphManager gm, ProxyManager pm) {
		ExecutorService es = Executors.newCachedThreadPool();

		boolean threadsEnded = false;
		boolean allUsersProcceeded = false;
		
		//начинаем проходить все ноды для запросов по данным
		gm.startUsersDataProcessing();	
		
		//в 10 потоков начинаем запрашивать данные по юзерам
		for (int i = 0; i < USERDATA_THREADS; i++) {
			Runnable r = new UserDataThread(gm, pm, i);
			es.execute(r);
		}
		
		es.shutdown();
		
		try {
			//подождем годик - другой
			threadsEnded = es.awaitTermination(365, TimeUnit.DAYS);
		} 
		catch (Exception e) {
			System.out.println("MainClass.main() Exception caught" + e.toString());
		}
		
		//добавим отладочную печать
		if (threadsEnded) {
			System.out.println("MainClass.getUserData():all processes ended");
			
			allUsersProcceeded = gm.checkAllProccessingsEnded();
			if (allUsersProcceeded) {
				System.out.println("MainClass.getUserData() all users proceed");
			} else {
				System.out.println("MainClass.getUserData() not all users proceed, error!");
			}
			
		} else { 
			System.out.println("MainClass.getUserData() awaittermination error");
		}
		
		//если дождались завершения, проверим, что все процессы c бд завершены
		return threadsEnded ? allUsersProcceeded : false;
	}
	
	private static long getHeadUserId(String screenName) {
		long id = INVALID_VALUE;
        DefaultHttpClient httpclient = new DefaultHttpClient();
        
        //вернувшийся текст
		String responseText = null;
		
		try {
			HttpGet getRequest = new HttpGet("https://api.twitter.com/1/users/show.json?screen_name=" + screenName);
			
			//делаем запрос
		    HttpResponse httpResponse = httpclient.execute(getRequest);
		    HttpEntity entity = httpResponse.getEntity();
		    //сохраняем текст респонса
		    responseText = new String(EntityUtils.toString(entity));

		    EntityUtils.consume(entity);
		} catch (Exception e) {
			System.out.println("MainClass.getHeadUserId() exception caught:" + e);
		}
		finally {
            httpclient.getConnectionManager().shutdown();
		}

		//проверка в лоб на несуществующего юзера из-за другого формата ошибки
		if (responseText.contains("Sorry, that page does not exist")) {
			System.out.println("MainClass.getHeadUserId() : no user with name " + screenName + " found");
			
		} else {
			if (responseText != null) {
				//пробуем посмотреть, ошибка или нет
				Responses.ErrorResponse errorResponse = Responses.parseErrorResponse(responseText);
				if (errorResponse != null && errorResponse.error != null) {
					String error = errorResponse.error;
					//проверим ошибку
					if (error.contains("Rate limit exceeded")) {
						//превышен лимит запросов
						System.out.println("MainClass.getHeadUserId() Rate limit exceeded:" + responseText);
						
					} else if (error.contains("User has been suspended")) {
						System.out.println("MainClass.getHeadUserId() user " + screenName + " was suspended");
						
					} else {
						System.out.println("MainClass.getHeadUserId() unexpected error " + responseText);
					}
					
				} else {
					//Пробуем распарсить 
					Responses.UserDataResponse userData = Responses.parseUserDataResponse(responseText);
					
					if (userData != null) {
						id = userData.id;
					} else {
						System.out.println("MainClass.getHeadUserId() cant parse userdata " + responseText);
					}
				}
			}
		}
		
		
		return id;
	}
	
	private static boolean getUsersFollowers(GraphManager gm, ProxyManager pm, int hopsCount) {
		boolean threadsEnded = false;
		boolean allUsersProceed = false;
		
		for (int i = 0; i < hopsCount; i++) {
			//начинаем обработку в граф-менеджере
			gm.startFollowersProcessing();

			ExecutorService es = Executors.newCachedThreadPool();
			
			//1,5,20
			int threadCount = 0;
			if (i == 0) {
				threadCount = 1;
			}
			else if (i == 1) {
				threadCount = 5;
			} else {
				threadCount = 20;
			}
			//создаем потоки
			for (int j = 0; j < threadCount; j++) {
				Runnable r = new FollowersThread(gm, pm, j);
				es.execute(r);
			}
			
			es.shutdown();
			
			threadsEnded = false;
			allUsersProceed = false;
			
			try {
				//подождем годик - другой
				threadsEnded = es.awaitTermination(365, TimeUnit.DAYS);
			} 
			catch (Exception e) {
				System.out.println("MainClass.main() Exception caught" + e.toString());
			}
			
			if (threadsEnded) {
				//Выводим количество людей и связей:
				System.out.println("MainClass.main() total people count:" + gm.getTotalUsersCount() + " total relationships:" + gm.getTotalUsersRelationshipsCount());
				
				//записываем флаг, что все юзеры обработаны
				allUsersProceed = gm.checkAllProccessingsEnded();
				
				//проверяем, что все потоки прошли
				System.out.println("MainClass.main() all proccesess ended: " + allUsersProceed);
				
				if (!allUsersProceed)
					break;
				
			} else {
				System.err.println("awaitTermination error - FollowersThreads");
				break;
			}
		}
		
		return threadsEnded ? allUsersProceed : false;
	}
}
